package cn.org.xuanguang.kepler.hormos.rdb.jpa.mapper;


import cn.org.xuanguang.kepler.hormos.rdb.dml.warrper.ColumnWrapperContext;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.*;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.generation.GenerationValues;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.generation.JPAProvider;
import cn.org.xuanguang.kepler.hormos.rdb.util.EnumUtils;
import cn.org.xuanguang.kepler.hormos.rdb.util.StyleUtil;
import cn.org.xuanguang.kepler.metadata.relational.KeplerMetaColumn;
import cn.org.xuanguang.kepler.metadata.relational.KeplerMetaTable;
import cn.org.xuanguang.kepler.metadata.relational.KeplerTableType;
import cn.org.xuanguang.kepler.util.StringUtil;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * entity到元数据的映射工具类
 *  <p>
 *   元数据操作
 *        1、entity类转表元数据
 *        2、列转实体类，包括主键、是否null等
 *   sql操作
 *        1、update，insert，列信息，值信息
 *        2、select，查询条件，列信息，值信息
 *        3、delete，删除条件，列信息，值信息
 *  *  3、
 *  </p>
 * @author xuanguang
 * @since 2.0
 */
public class EntityMetaTableUtils {
    // 日志
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    // 元数据操作
    /**
     * entity类转表元数据
     *
     * @param mapperEntity
     * @return
     */
    public static KeplerMetaTable getMetaTable(Class<?> mapperEntity) {
        KeplerMetaTable keplerMetaTable = new KeplerMetaTable();
        // 表名
        keplerMetaTable.setTableName(getTableName(mapperEntity));
        //CatalogName名
        keplerMetaTable.setCatalogName(getCatalogName(mapperEntity));
        // scheam名
        keplerMetaTable.setSchemaName(getSchemaName(mapperEntity));
        // 列信息
        keplerMetaTable.setColumns(getColumns(mapperEntity));
        // 0.4.1 支持table，不支持view
        keplerMetaTable.setTableType(KeplerTableType.TABLE);
        return keplerMetaTable;
    }


    private static String getTableName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        return table == null ? clazz.getSimpleName() : table.name();
    }

    private static String getCatalogName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        if (!StringUtil.isEmpty(table.catalogName())) {
            return table.catalogName();
        }
        return table.schemaName();
    }

    private static String getSchemaName(Class<?> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        if (!StringUtil.isEmpty(table.schemaName())) {
            return table.schemaName();
        }
        return table.schemaName();
    }

    /**
     * 根据提供的类，获取其所有字段对应的KeplerMetaColumn对象列表。
     * 这个方法会递归遍历类及其父类的字段，将每个字段封装为KeplerMetaColumn对象，并添加到列表中。
     * 最后，会检查列表中是否存在重名的字段。
     *
     * @param clazz 需要解析字段的类。开始时传入具体子类的Class对象，然后递归处理其父类。
     * @return KeplerMetaColumn列表，包含了类及其父类中所有的字段信息。
     */
    private static List<KeplerMetaColumn> getColumns(Class<?> clazz) {
        // 初始化列列表
        List<KeplerMetaColumn> keplerMetaColumns = new LinkedList<>();
        while (clazz != null) {
            // 遍历当前类的字段，将其封装为KeplerMetaColumn对象并添加到列表
            createkeplerMetaColumns(keplerMetaColumns, clazz);
            // 获取当前类的父类，继续遍历
            clazz = clazz.getSuperclass();
        }
        // 检查列表中是否存在重名的字段
        checkRepeatColumn(keplerMetaColumns);
        return keplerMetaColumns;
    }
    private static void createkeplerMetaColumns(List<KeplerMetaColumn> keplerMetaColumns, Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            field.setAccessible(true);
            KeplerMetaColumn keplerMetaColumn = null;
            // 获取列对象元数据注解，必须要添加@Column注解
            if (field.isAnnotationPresent(Column.class) && field.isAnnotationPresent(Id.class)) {
                Column columnAnnotation = field.getAnnotation(Column.class);
                // todo 格式判断，是否需要驼峰写法等
                keplerMetaColumn = buildColumn(columnAnnotation, field.getName());
                keplerMetaColumn.setPrimaryKey(true);
            } else if (field.isAnnotationPresent(Column.class) && !field.isAnnotationPresent(Id.class)) {
                Column columnAnnotation = field.getAnnotation(Column.class);
                // todo 格式判断，是否需要驼峰写法等
                keplerMetaColumn = buildColumn(columnAnnotation, field.getName());
            } else if (field.isAnnotationPresent(Ignore.class)) {
                // 排除列
                keplerMetaColumn = null;
            }
            // todo 乐观锁处理
            if (field.isAnnotationPresent(Version.class)) {
            }
            if (keplerMetaColumn != null) {
                keplerMetaColumns.add(keplerMetaColumn);
            }
        });

    }

    private static void checkRepeatColumn(List<KeplerMetaColumn> keplerMetaColumns) {
        keplerMetaColumns.stream().forEach(keplerMetaColumn -> {
//            判断非null对象比较
            if (keplerMetaColumn != null) {
                // 判断重复
                if (keplerMetaColumns.stream().filter(
                        column -> column != null &&
                                column.getColumnName().equals(keplerMetaColumn.getColumnName())).count() > 1) {
                    // 如果有重复，需要判断是否子类还是超类，保留子类的字段
                    keplerMetaColumns.removeIf(column -> column != null &&
                            column.getColumnName().equals(keplerMetaColumn.getColumnName()));
                    throw new RuntimeException("字段" + keplerMetaColumn.getColumnName() + "重复");
                }
            }
        });
    }

    private static KeplerMetaColumn buildColumn(Column column, String filedName) {
        KeplerMetaColumn keplerMetaColumn = new KeplerMetaColumn();
        if ("".equals(column.columnName())) {
            keplerMetaColumn.setColumnName(filedName);
        } else {
            keplerMetaColumn.setColumnName(column.columnName());
        }
        // 此处使用definiton 存储 原始对象的filed字段，在使用的时候，如果是jpa映射需要用到
        keplerMetaColumn.setColumnDefinition(filedName);
        keplerMetaColumn.setColumnLength(column.columnLength());
        keplerMetaColumn.setColumnType(column.columnType());
        keplerMetaColumn.setAutoIncrement(column.autoIncrement());
        keplerMetaColumn.setDefaultValue(column.defaultValue());
        keplerMetaColumn.setPartitionField(column.partitionField());
        keplerMetaColumn.setPosition(column.position());
        keplerMetaColumn.setPrecision(column.precision());
        keplerMetaColumn.setPrimaryKey(column.primaryKey());
        keplerMetaColumn.setUnique(column.unique());
        keplerMetaColumn.setPrecision(column.precision());
        keplerMetaColumn.setNullable(column.nullable());
        keplerMetaColumn.setScale(column.scale());
        keplerMetaColumn.setJdbcType(column.jdbcType());
        keplerMetaColumn.setComment(column.comment());

        return keplerMetaColumn;

    }
}
